package main

import (
	"flag"
	"fmt"
	"grpc.getaway.adminspro.padmins.com/pkg/config"
	"grpc.getaway.adminspro.padmins.com/pkg/libs/db"
	"grpc.getaway.adminspro.padmins.com/pkg/libs/utils"
	"log"
	"strconv"
	"strings"
)

func main() {
	var serviceName, tableName string
	var curd bool
	flag.StringVar(&tableName, "table", "admin", "表名")
	flag.StringVar(&serviceName, "service", "admin", "服务名")
	flag.BoolVar(&curd, "curd", true, "生成CURD方法")
	flag.Parse()

	if tableName == "" {
		panic("表名不能为空")
	}

	aTable := strings.Split(strings.TrimSpace(tableName), ",")
	tablePris := map[string]string{}
	tableLists := map[string]map[string]string{}
	tableTexts := map[string]string{}
	if serviceName != "" {
		fmt.Println(buildHead(serviceName))
	}

	for _, t := range aTable {
		if t == "" {
			panic("表名不能为空")
		}
		data, pri, lists, tableText := getTableMate(t)
		tablePris[t] = pri
		tableLists[t] = lists
		tableTexts[t] = tableText
		fmt.Println(buildMessage(t, tableText, data))
	}

	if curd {
		fmt.Println(buildService(serviceName, aTable, tablePris, tableLists, tableTexts))
	}

}

func getdb() *db.Db {
	dsn := fmt.Sprintf(
		"%s:%s@tcp(%s:%d)/%s?charset=%s",
		config.Config.Db.Username,
		config.Config.Db.Password,
		config.Config.Db.Host,
		config.Config.Db.Port,
		config.Config.Db.Dbname,
		config.Config.Db.Charset,
	)
	return db.New(db.Open(config.Config.Db.Driver, dsn))
}

func getTableMate(tableName string) ([]map[string]interface{}, string, map[string]string, string) {
	Db := getdb()
	// 简单的调用Query就可以得到结果
	tableData, e := Db.Find("SELECT * FROM `information_schema`.`tables` WHERE TABLE_SCHEMA=? AND table_name=?", config.Config.Db.Dbname, tableName)

	if e != nil {
		log.Fatalln(e)
	}
	// 简单的调用Query就可以得到结果
	data, e := Db.Query("SELECT * FROM `information_schema`.`columns` WHERE TABLE_SCHEMA=? AND table_name=? ORDER BY ORDINAL_POSITION", config.Config.Db.Dbname, tableName)

	if e != nil {
		log.Fatalln(e)
	}

	pri := ""
	//tableText := ""
	lists := map[string]string{}
	for _, mate := range data {
		COLUMN_NAME := mate["COLUMN_NAME"].(string)
		if mate["COLUMN_KEY"] == "PRI" && pri != "" {
			pri = COLUMN_NAME
		}

		COLUMN_COMMENT := strings.Split(mate["COLUMN_COMMENT"].(string), ":")

		if len(COLUMN_COMMENT) == 2 {
			lists[COLUMN_NAME] = mate["COLUMN_COMMENT"].(string)
		}
	}

	if pri == "" {
		pri = data[0]["COLUMN_NAME"].(string)
	}

	return data, pri, lists, strings.Replace(tableData["TABLE_COMMENT"].(string), "表", "", 1)
}

func buildHead(serviceName string) string {
	str := fmt.Sprintln("syntax = \"proto3\";")
	str += fmt.Sprintf("package pkg.proto.%s;\noption go_package = \"./%s;pb%s\";\n", serviceName, serviceName, utils.UcFirst(serviceName))
	str += fmt.Sprintln("import \"common/businessCommonQuery.proto\";\n")
	return str
}

func buildMessage(tableName, tableText string, data []map[string]interface{}) string {

	if len(data) == 0 {
		log.Fatalln(tableName + "表不存在")
	}

	tableNames := strings.Split(tableName, "_")

	structName := ""

	for _, name := range tableNames {
		structName += utils.UcFirst(name)
	}

	message := fmt.Sprintf("// %s\n", tableText)
	message += fmt.Sprintf("message %s {\n", structName)

	maxLength := 0

	for i, mate := range data {
		l := len(fmt.Sprintf("%s=%d;", mate["COLUMN_NAME"], i+1))
		if l > maxLength {
			maxLength = l
		}
	}

	for i, mate := range data {
		DATA_TYPE := ""
		switch mate["DATA_TYPE"] {
		case "int":
			DATA_TYPE = "int64"
			break
		case "tinyint":
			DATA_TYPE = "int32"
			break
		default:
			DATA_TYPE = "string"
		}

		inject_tag := ""

		if mate["COLUMN_KEY"] != "PRI" && mate["DATA_TYPE"] != "datetime" {
			inject_tag = fmt.Sprintf(" @inject_tag: json:\"%s\"", mate["COLUMN_NAME"])
		}

		COLUMN_COMMENT := utils.UcFirst(mate["COLUMN_NAME"].(string))
		if mate["COLUMN_COMMENT"] != "" {
			COLUMN_COMMENT = mate["COLUMN_COMMENT"].(string)
		}

		message += fmt.Sprintf("  %-6s %-"+strconv.Itoa(maxLength)+"s // %s%s\n", DATA_TYPE, fmt.Sprintf("%s=%d;", mate["COLUMN_NAME"], i+1), COLUMN_COMMENT, inject_tag)
	}
	message += fmt.Sprint("}\n")
	return message
}

func buildService(serviceName string, tables []string, tablePris map[string]string, tableLists map[string]map[string]string, tableTexts map[string]string) string {
	rpc := ""
	re := ""
	for _, tableName := range tables {

		tableNames := strings.Split(tableName, "_")
		table := ""

		for i, name := range tableNames {
			if i == 0 {
				table = name
			} else {
				table += utils.UcFirst(name)
			}
		}
		ucTable := utils.UcFirst(table)
		pri := tablePris[tableName]
		lists := tableLists[tableName]
		tableText := tableTexts[tableName]

		re += buildIndex(ucTable, tableText)
		re += buildList(ucTable, tableText, lists)
		re += buildDetail(ucTable, pri, tableText)
		re += buildAdd(ucTable, pri, tableText)
		re += buildEdit(ucTable, tableText)
		re += buildDel(ucTable, pri, tableText)
		re += buildMulti(ucTable, pri, tableText)
		re += "\n\n"

		rpc += fmt.Sprintf("  // %s列表\n", tableText)
		rpc += fmt.Sprintf("  rpc %sIndex(%sIndexReq) returns (%sIndexResp);\n", table, ucTable, ucTable)
		rpc += fmt.Sprintf("  // %s枚举字段列表选项\n", tableText)
		rpc += fmt.Sprintf("  rpc %sList(%sListReq) returns (%sListResp);\n", table, ucTable, ucTable)
		rpc += fmt.Sprintf("  // %s详情\n", tableText)
		rpc += fmt.Sprintf("  rpc %sDetail(%sDetailReq) returns (%sDetailResp);\n", table, ucTable, ucTable)
		rpc += fmt.Sprintf("  // %s添加\n", tableText)
		rpc += fmt.Sprintf("  rpc %sAdd(%sAddReq) returns (%sAddResp);\n", table, ucTable, ucTable)
		rpc += fmt.Sprintf("  // %s编辑\n", tableText)
		rpc += fmt.Sprintf("  rpc %sEdit(%sEditReq) returns (%sEditResp);\n", table, ucTable, ucTable)
		rpc += fmt.Sprintf("  // %s删除\n", tableText)
		rpc += fmt.Sprintf("  rpc %sDel(%sDelReq) returns (%sDelResp);\n", table, ucTable, ucTable)
		rpc += fmt.Sprintf("  // %s批量操作\n", tableText)
		rpc += fmt.Sprintf("  rpc %sMulti(%sMultiReq) returns (%sMultiResp);\n\n\n", table, ucTable, ucTable)
	}
	service := fmt.Sprintf("service %s {\n%s}\n", serviceName, rpc)
	return re + service
}

func buildIndex(table, tableText string) string {
	str := fmt.Sprintf("// %s列表请求\n", tableText)
	str += fmt.Sprintf("message %sIndexReq {\n", table)
	str += fmt.Sprintln("  pkg.proto.common.BusinessCommonQuery businessCommonQuery=1; // 公共查询")
	str += fmt.Sprintln("  bool show_total=2;                                          // 是否展示total:true=是,false=否")
	str += fmt.Sprintln("}")

	str += fmt.Sprintf("// %s列表响应\n", tableText)
	str += fmt.Sprintf("message %sIndexResp {\n", table)
	str += fmt.Sprintf("  repeated %s rows=1; // 列表 @inject_tag: json:\"rows\"\n", table)
	str += fmt.Sprintln("  int64 total=2;         // 总数 @inject_tag: json:\"total\"")
	str += fmt.Sprintln("}")

	return str
}

func buildList(table, tableText string, lists map[string]string) string {
	str := fmt.Sprintf("// %s枚举字段列表选项请求\n", tableText)
	str += fmt.Sprintf("message %sListReq {}\n", table)
	str += fmt.Sprintf("// %s枚举字段列表选项响应\n", tableText)
	str += fmt.Sprintf("message %sListResp {\n", table)
	i := 1
	maxLen := 0
	for s, _ := range lists {
		l := len(fmt.Sprintf("%s=%d;", s, i))
		if l > maxLen {
			maxLen = l
		}
		i++
	}
	i = 1
	for s, m := range lists {
		str += fmt.Sprintf("  map<string, string> %-"+strconv.Itoa(maxLen)+"s // %s\n", fmt.Sprintf("%s=%d;", s, i), m)
		i++
	}
	str += fmt.Sprintln("}")
	return str
}

func buildDetail(table, pri, tableText string) string {
	str := fmt.Sprintf("// %s详情请求\n", tableText)
	str += fmt.Sprintf("message %sDetailReq {\n  int64 %s=1; // 主键\n}\n", table, pri)
	str += fmt.Sprintf("// %s详情响应\n", tableText)
	str += fmt.Sprintf("message %sDetailResp {\n  %s row=1; // 详情 @inject_tag: json:\"row\"\n}\n", table, table)
	return str
}

func buildAdd(table, pri, tableText string) string {
	str := fmt.Sprintf("// %s添加请求\n", tableText)
	str += fmt.Sprintf("message %sAddReq {\n  %s %s=1;\n}\n", table, table, utils.LcFirst(table))
	str += fmt.Sprintf("// %s添加响应\n", tableText)
	str += fmt.Sprintf("message %sAddResp {\n int64 %s=1; // 主键 @inject_tag: json:\"%s\"\n}\n", table, pri, pri)
	return str
}

func buildEdit(table, tableText string) string {
	str := fmt.Sprintf("// %s编辑请求\n", tableText)
	str += fmt.Sprintf("message %sEditReq {\n  %s %s=1;\n}\n", table, table, utils.LcFirst(table))
	str += fmt.Sprintf("// %s编辑响应\n", tableText)
	str += fmt.Sprintf("message %sEditResp {\n int64 rowCount=1; // 影响行数 @inject_tag: json:\"rowCount\"\n}\n", table)
	return str
}

func buildDel(table, pri, tableText string) string {
	str := fmt.Sprintf("// %s删除请求\n", tableText)
	str += fmt.Sprintf("message %sDelReq {\n repeated int64 %s=1; // 主键\n}\n", table, pri)
	str += fmt.Sprintf("// %s删除响应\n", tableText)
	str += fmt.Sprintf("message %sDelResp {\n int64 rowCount=1; // 影响行数 @inject_tag: json:\"rowCount\"\n}\n", table)
	return str
}

func buildMulti(table, pri, tableText string) string {
	str := fmt.Sprintf("// %s批量操作请求\n", tableText)
	str += fmt.Sprintf("message %sMultiReq {\n", table)
	str += fmt.Sprintf("  repeated int64 %s=1; // 主键 \n", pri)
	str += fmt.Sprintf("  string field=2; // 字段\n")
	str += fmt.Sprintf("  string value=3; // 值\n")
	str += fmt.Sprintln("}")
	str += fmt.Sprintf("// %s批量操作响应\n", tableText)
	str += fmt.Sprintf("message %sMultiResp {\n int64 rowCount=1; // 影响行数 @inject_tag: json:\"rowCount\"\n}\n", table)
	return str
}
